//
//  BitArray.m
//  SimulacraDB
//
//  Created by Andre Cohen on 8/9/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "ByteArray.h"


@implementation ByteArray

+ (ByteArray *)createFromInt:(int)val {
	ByteArray *array = [[[ByteArray alloc] init] autorelease];
	[array appendInt:val];
	return array;
}

+ (ByteArray *)createFromFloat:(double)val {
	ByteArray *array = [[[ByteArray alloc] init] autorelease];
	[array appendFloat:val];
	return array;
}

+ (ByteArray *)createFromString:(NSString *)string {
	return [[[ByteArray alloc] initWithString:string] autorelease];
}

+ (ByteArray *)createWithSize:(int)size {
	ByteArray *array = [[[ByteArray alloc] init] autorelease];
	int i;
	for(i=0;i<size;i++){
		[array appendChar:0];
	}
	return array;
}

- (id) init {
	[super init];
	data = [[[NSMutableArray alloc] init] autorelease];
	return self;
}

- (id)initWithData:(char *)raw length:(int)len {
	[self init];
	
	int i;
	for(i=0;i<len;i++){
		[self appendChar:raw[i]];
	}
	return self;
}

- (id)initWithString:(NSString *)string {
	[self init];
	[self appendString:string];
	return self;
}

- (id)initWithNSData:(NSData *)raw {
	[self init];
	
	char *array = (char *)calloc(sizeof(char),[raw length]);
	[raw getBytes:array];
	int i;
	for(i=0;i<[raw length];i++)
		[self appendChar:array[i]];
	free(array);
	
	return self;
}

- (int)appendChar:(char)value {
	[data addObject:[NSNumber numberWithChar:value]];
	return [data count];
}

- (int)appendInt:(int)value {
	[self appendChar:(value>>8)];
	return [self appendChar:((value<<8)>>8)];
}

- (double)appendFloat:(double)value {
	char d[] = {0,0,0,0,0,0,0,0};
	memcpy(d,&value,8);
	[self appendChar:d[0]];
	[self appendChar:d[1]];
	[self appendChar:d[2]];
	[self appendChar:d[3]];
	[self appendChar:d[4]];
	[self appendChar:d[5]];
	[self appendChar:d[6]];
	[self appendChar:d[7]];
	
	return value;
}

- (int)appendString:(NSString *)value {
	int i;
	for(i=0;i<[value length];i++)
		[self appendChar:[value characterAtIndex:i]];
	return [data count];
}

- (int)appendByteArray:(ByteArray *)value {
	int i;
	for(i=0;i<[value count];i++)
		[self appendChar:[value getCharFromLocation:i]];
	return [data count];
}

- (char)getBitFromLocation:(int)loc {
	if(floor(loc/CHAR_BIT)>=[data count])
		return -1;
	char mask = (0x01 << (CHAR_BIT-(loc%CHAR_BIT)-1));
	char d = [self getCharFromLocation:floor(loc/(double)CHAR_BIT)];
	return (d & mask)==mask;
}

- (char)getCharFromLocation:(int)loc {
	if(loc>=[data count])
		return 0xff;
	return [[data objectAtIndex:loc] charValue];
}

- (int)getIntFromLocation:(int)loc {
	if(loc+1>=[data count])
		return 0xffff;
	return ((int)[self getCharFromLocation:loc]<<8)+(unsigned char)[self getCharFromLocation:loc+1];
}

- (double)getFloatFromLocation:(int)loc {
	if(loc+7>=[data count])
		return 0xffffffff;
	char parts[] = {0,0,0,0,0,0,0,0};
	parts[0] = (unsigned char)[self getCharFromLocation:loc];
	parts[1] = (unsigned char)[self getCharFromLocation:loc+1];
	parts[2] = (unsigned char)[self getCharFromLocation:loc+2];
	parts[3] = (unsigned char)[self getCharFromLocation:loc+3];
	parts[4] = (unsigned char)[self getCharFromLocation:loc+4];
	parts[5] = (unsigned char)[self getCharFromLocation:loc+5];
	parts[6] = (unsigned char)[self getCharFromLocation:loc+6];
	parts[7] = (unsigned char)[self getCharFromLocation:loc+7];
	double *d = (double *)parts;
	double dd = *d;
	return dd;
}

- (void)setBitAtLocation:(int)loc value:(BOOL)val {
	if(floor(loc/CHAR_BIT)>=[data count])
		return;
	
	NSMutableArray *array = (NSMutableArray *)[self toArray:[self getCharFromLocation:floor(loc/CHAR_BIT)]];

	[array replaceObjectAtIndex:(loc%CHAR_BIT) withObject:[NSNumber numberWithBool:val]];

	[self setCharAtLocation:floor(loc/CHAR_BIT) value:[self fromArray:array]];
}
- (void)setCharAtLocation:(int)loc value:(char)val {
	if(loc>=[data count])
		return;
	[data replaceObjectAtIndex:loc withObject:[NSNumber numberWithChar:val]];
}
- (void)setIntAtLocation:(int)loc value:(int)val {
	if(loc+1>=[data count])
		return;
	[data replaceObjectAtIndex:loc withObject:[NSNumber numberWithChar:(val>>8)]];
	[data replaceObjectAtIndex:loc+1 withObject:[NSNumber numberWithChar:((val<<8)>>8)]];
}
- (void)setStringAtLocation:(int)loc value:(NSString *)val{
	if(loc+[val length]-1>=[data count])
		return;
	int i;
	for(i=0;i<[val length];i++)
		[self setCharAtLocation:loc+i value:[val characterAtIndex:i]];
}

- (NSString *)toString {
	return [self getStringFromLocation:0 length:[data count]-1];
}

- (NSData *)toNSData {
	NSMutableData *raw = [[[NSMutableData alloc] init] autorelease];
	unsigned char *array = (unsigned char *)calloc(sizeof(char),[self count]);
	int i;
	for(i=0;i<[self count];i++)
		array[i] = [self getCharFromLocation:i];
	[raw appendBytes:array length:[self count]];
	return raw;
}

- (NSArray *)toArray:(char)val {
	NSMutableArray *bitfield = [[[NSMutableArray alloc] init] autorelease];
	int i;
	for(i=0;i<CHAR_BIT;i++){
		bool b = (val & (0x01 << (CHAR_BIT-i-1))) != 0;
		[bitfield insertObject:[NSNumber numberWithBool:b] 
					   atIndex:i];
	}
	return bitfield;
}
- (char)fromArray:(NSArray *)array {
	char val = 0;
	int i;
	for(i=0;i<CHAR_BIT;i++)
		if([[array objectAtIndex:i] boolValue])
			val = val | (0x01 << (CHAR_BIT-(i%CHAR_BIT)-1));
	return val;
}

- (NSString *)getStringFromLocation:(int)loc length:(int)len{
	if(loc+len>=[data count])
		return nil;
	NSMutableString *string = [[[NSMutableString alloc] initWithString:@""] autorelease];
	int i;
	for(i=loc;i<=loc+len;i++)
		[string appendFormat:@"%c",[self getCharFromLocation:i]];
	return string;
}

- (char)extractCharFromLocation:(int)loc{
	char object = [self getCharFromLocation:loc];
	[self extractFrom:loc length:1];
	return object;
}

- (int)extractIntFromLocation:(int)loc{
	int object = [self getIntFromLocation:loc];
	[self extractFrom:loc length:2];
	return object;
}
- (NSString *)extractStringFromLocation:(int)loc length:(int)len{
	NSString *object = [self getStringFromLocation:loc length:len];
	[self extractFrom:loc length:len];
	return object;
}

- (bool)extractFrom:(int)loc length:(int)len{
	if(loc+len>=[data count])
		return false;
	[data removeObjectsInRange:NSMakeRange(loc,len)];
	return true;
}


- (int)count {
	return [data count];
}

- (int)bitCount {
	return [data count]*CHAR_BIT;
}

- (NSString *)description {
	NSMutableString *desc = [[[NSMutableString alloc] initWithString:@""] autorelease];
	int i;
	for(i=0;i<[data count];i++)
		[desc appendFormat:@"%02x ",(unsigned char)[self getCharFromLocation:i]];
	return desc;
}

- (NSString *)bitDescription {
	NSMutableString *desc = [[[NSMutableString alloc] initWithString:@""] autorelease];
	int i=0;
	for(i=0;i<[self bitCount];i++){
		[desc appendFormat:@"%d",([self getBitFromLocation:i]==1)];
	}
	return desc;
}

@end
